home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2000 #5
/
Amiga Plus CD - 2000 - No. 5.iso
/
Tools
/
Dev
/
FPSE_src
/
cpu2.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-01
|
13KB
|
506 lines
/*
R3000 emu
(C) 1999 BERO
*/
#include "fpse.h"
R3000_REG reg;
// int stop;
void printpc(void)
{
PRINTF("%08x:",(int)(PC-4));
}
void Exception(int cd)
{
// if (cd == E_Bp*4) cd = E_Sys*4; // Avoid break exeception
if (in_slot) {
EPC=PC-4; CAUSE=cd | 0x80000000;
} else {
EPC=PC;
CAUSE = cd;
}
PRINTF("Exception:%x\n",cd);
// CAUSE = (CAUSE & ~0x3c) | cd;
SR = (SR & ~0x3f)| ((SR<<2)&0x3f);;
PC=0x80000080;
SETPC(PC);
if (exception_handler()) FPSE_Flags |= STOP;
SETPC(PC);
}
/* hwè±Ý */
void Interrupt(void)
{
// PRINTF("Interrupt %x\n",PC);
if (SR&1) { /* èݳêÄé© */
if (SR & 0x400) { /* wèè±ÝͳêÄé© */
Exception(0x400);
}
}
}
void Reset(void)
{
memset(®,0,sizeof(reg));
PC = 0xbfc00000;
/* kernel mode */
SETPC(PC);
}
#ifndef INT64
static void multu(UINT32 v1,UINT32 v2)
{
UINT32 v1h,v1l,v2h,v2l;
UINT32 ll,hl,lh,hh,mid,mid2;
v1l = (UINT16)v1;
v1h = ((UINT32)v1)>>16;
v2l = (UINT16)v2;
v2h = ((UINT32)v2)>>16;
ll = v1l*v2l;
hl = v1h*v2l;
lh = v1l*v2h;
hh = v1h*v2h;
/*
|ll|ll|
|lh|lh|
|hl|hl|
|hh|hh|
--------------
| mid |
|carry|
*/
mid = hl+lh;
if (mid<hl) hh+=0x10000;
mid2 = mid + (ll>>16);
if (mid2<mid) hh+=0x10000;
rLO = (UINT16)ll|(mid2<<16);
rHI = hh+(mid>>16);
}
static void mult(INT32 v1,INT32 v2)
{
int sign = (v1^v2)<0;
if (v1<0) {v1 = -v1;}
if (v2<0) {v2 = -v2;}
multu(v1,v2);
if (sign) {
rLO = -rLO;
rHI = ~rHI;
if (rLO==0) rHI++;
}
}
#endif
void bioscheck(int pc)
{
switch(pc) {
case 0xc0:
case 0xb0:
case 0xa0:
if (biosprint(pc)) {
/* ñT|[g */
// stop = 1;
}
SETPC(PC);
break;
}
}
#define JUMP(pc) { UINT32 newpc=(pc); \
FPSE_Flags |= IN_SLOT; \
doInst(); \
FPSE_Flags &= ~IN_SLOT; \
PC=newpc; }
#define NOT_IMPREMENT(cd) { printf("not imprement %s: %08x\n",cd,(int)code); \
FPSE_Flags |= STOP; }
void setpc(int pc)
{
PC = pc; SETPC(PC);
}
#define INSTSIZE (0x280000/4)
static char flg[INSTSIZE];
static int nopcounter;
extern int breakpoint;
// #define SUPPORT_HBP
#ifdef SUPPORT_HBP
#define CHECK_EXECBREAK(adr) \
if ((CPR0[7] & 0x01000000)==0x01000000) && (adr & CPR0[11])==CPR0[3] ) {\
/* read break happen */ \
}
#define CHECK_READBREAK(adr) \
if ((CPR0[7] & 0x06000000)==0x06000000) && (adr & CPR0[9])==CPR0[5] ) {\
/* read break happen */ \
}
#define CHECK_WRITEBREAK(adr) \
if ((CPR0[7] & 0x0a000000)==0x0a000000) && (adr & CPR0[9])==CPR0[5] ) {\
/* read break happen */ \
}
#else
#define CHECK_EXECBREAK(adr)
#define CHECK_READBREAK(adr)
#define CHECK_WRITEBREAK(adr)
#endif
void doInst(void)
{
UINT32 code;
/*
if (PC==breakpoint) watch();
*/
if (stop) return;
CHECK_EXECBREAK(PC);
code = FETCH(PC);
if (disasmflg) {
UINT32 adr=PC;
static char strbuf[256];
if (adr>0xbfc00000) adr = adr-0xbfc00000+0x200000;
else adr&=0x1fffff;
if (!flg[adr/4] || debug) {
flg[adr/4]=1;
disasm(strbuf,code,PC);
printf("%08x %08x %s\n",(int)PC,(int)code,strbuf);
}
}
PC+=4;
/*
if (reg.r[0]) {
PRINTF("reg0 boken\n");
FPSE_Flags |= STOP;
}
*/
if (!code) {
/* nop */
nopcounter++;
if (nopcounter>100) {
FPSE_Flags |= STOP;
printpc();
PRINTF("too long nop\n");
}
return;
}
nopcounter = 0;
switch(code>>26) {
case SPECIAL:
switch(code&63) {
case SLL: rd = (UINT32)rt << ((code>>6)&31); break;
case SRL: rd = (UINT32)rt >> ((code>>6)&31); break;
case SRA: rd = (INT32)rt >> ((code>>6)&31); break;
case SLLV: rd = (UINT32)rt << (rs&31); break;
case SRLV: rd = (UINT32)rt >> (rs&31); break;
case SRAV: rd = (INT32)rt >> (rs&31); break;
case ADD:
#if 1
rd = rs + rt;
#else
{
int tmp = rs + rt;
/* ª¯¶ && OÆã̪á¤@*/
if ((INT32)(rs^rt)>=0 && (INT32)(rs^tmp)<0) {
EXCEPTION(E_Ovf);
} else {
rd = tmp;
}
}
#endif
break;
case SUB:
#if 1
rd = rs - rt;
#else
{
int tmp = rs - rt;
/* ªá¤ && OÆã̪á¤@*/
if ((INT32)(rs^rt)<0 && (INT32)(rs^tmp)<0) {
EXCEPTION(E_Ovf);
} else {
rd = tmp;
}
}
#endif
break;
case ADDU: rd = rs + rt; break;
case SUBU: rd = rs - rt; break;
case AND: rd = rs & rt; break;
case OR: rd = rs | rt; break;
case XOR: rd = rs ^ rt; break;
case NOR: rd = ~(rs | rt); break;
case SLT: rd = ( (INT32)rs < (INT32) rt); break;
case SLTU: rd = ((UINT32)rs < (UINT32)rt); break;
case DIV: if (rt) {
rLO = ( INT32)rs/( INT32)rt;
rHI=( INT32)rs%( INT32)rt;
}
break;
case DIVU: if (rt) {
rLO = (UINT32)rs/(UINT32)rt;
rHI=(UINT32)rs%(UINT32)rt;
}
break;
#ifdef INT64
case MULT:
rLO = ((INT64)(INT32)rs*(INT32)rt);
rHI = ((INT64)(INT32)rs*(INT32)rt)>>32;
break;
case MULTU:
rLO = ((INT64)(UINT32)rs*(UINT32)rt);
rHI = ((INT64)(UINT32)rs*(UINT32)rt)>>32;
break;
#else
case MULT: mult(rs,rt); break;
case MULTU: multu(rs,rt); break;
#endif
case MFHI: rd = rHI; break;
case MFLO: rd = rLO; break;
case MTHI: rHI = rs; break;
case MTLO: rLO = rs; break;
case JALR: rd = PC+4; // reg.r[31] = PC+4;
case JR: JUMP(rs); SETPC(PC); bioscheck(PC); break;
case BREAK: EXCEPTION(E_Bp); break;
case SYSCALL:
PRINTF("syscall: %08x",(int)(reg.r[4]));
switch(reg.r[4]) {
case 0:PRINTF("Exception\n"); break;
case 1:PRINTF("EnterCriticalSection\n"); break;
case 2:PRINTF("ExitCriticalSection\n"); break;
default:PRINTF("%d\n",(int)(reg.r[4]));
}
EXCEPTION(E_Sys);
break;
default: NOT_IMPREMENT("special"); break;
}
break;
case BCOND:
switch(rtno){
case BLTZAL:reg.r[31]=PC+4;
case BLTZ: if ((INT32)rs< 0) { JUMP(PC + immS*4); } break;
case BGEZAL:reg.r[31]=PC+4;
case BGEZ: if ((INT32)rs>=0) { JUMP(PC + immS*4); } break;
default: NOT_IMPREMENT("bcond"); break;
}
break;
/* BRANCH/JUMP */
case JAL: reg.r[31] = PC+4;
case J: JUMP((PC&0xf0000000)|((code&0x03ffffff)<<2)); break;
case BNE: if (rt!=rs) { JUMP(PC + immS*4); } break;
case BEQ: if (rt==rs) { JUMP(PC + immS*4); } break;
case BLEZ: if ((INT32)rs<=0) { JUMP(PC + immS*4); } break;
case BGTZ: if ((INT32)rs> 0) { JUMP(PC + immS*4); } break;
/* ALU */
case ADDI:
#if 1
rt = rs + immS;
#else
{
int tmp = rs + immS;
/* ª¯¶ && OÆã̪á¤@*/
if ((INT32)(rs^immS)>=0 && (INT32)(rs^tmp)<0) {
EXCEPTION(E_Ovf);
} else {
rt = tmp;
}
}
#endif
break;
case ADDIU: rt = rs + immS; break;
case SLTI: rt = ( (INT32)rs < immS); break;
case SLTIU: rt = ((UINT32)rs < (UINT32)immS); break;
case ANDI: rt = rs & immU; break;
case ORI: rt = rs | immU; break;
case XORI: rt = rs ^ immU; break;
case LUI: rt = (code<<16); break;
/* COP */
case COP0:
switch(rsno) {
case MFC: rt = CPR0[rdno]; /*PRINTF("cop0:r %d\n",rdno);*/ break;
case CFC: rt = CCR0[rdno]; PRINTF("cop0:\n"); break;
case MTC: if (rdno!=13 && rdno!=14) CPR0[rdno] = rt;
PRINTF("cop0:w %d,%x\n",(int)rdno,(int)rt);
break;
case CTC: CCR0[rdno] = rt; /*PRINTF("cop0:\n");*/ break;
case 16:
if ((code&31)==16) { /* RFE */
SR = (SR & ~0xf)| ((SR>>2)&0xf);
PRINTF("rfe:%x\n",(int)SR);
break;
}
default: NOT_IMPREMENT("COP0"); break;
}
break;
case COP2:
switch(rsno) {
case MFC: cop2read(rdno ,CPR2); rt = CPR2[rdno]; break;
case CFC: cop2read(rdno+32,CPR2); rt = CCR2[rdno]; break;
case MTC: CPR2[rdno] = rt; cop2write(rdno ,CPR2); break;
case CTC: CCR2[rdno] = rt; cop2write(rdno+32,CPR2); break;
default:
if (cop2(code&0x1ffffff,CPR2))
FPSE_Flags |= STOP;
break;
}
break;
/* LOAD/STORE */
case SB:
CHECK_WRITEBREAK(adr);
write8(rs+immS,rt); break;
case SH: {
UINT32 adr = rs+immS;
CHECK_WRITEBREAK(adr);
if (adr&1) { EXCEPTION(E_DBE); }
else write16(adr,rt);
}
break;
case SW: {
UINT32 adr = rs+immS;
CHECK_WRITEBREAK(adr);
if (adr&3) { EXCEPTION(E_DBE); }
else write32(adr,rt);
}
break;
case SWL: {
UINT32 adr = rs + immS;
UINT32 data;
CHECK_WRITEBREAK(adr);
data = read32(adr&~3);
switch(adr&3) {
case 3: data = rt; break;
case 2: data = (data & 0xff000000) | (rt>> 8); break;
case 1: data = (data & 0xffff0000) | (rt>>16); break;
case 0: data = (data & 0xffffff00) | (rt>>24); break;
}
write32(adr&~3,data);
}
break;
case SWR: {
UINT32 adr = rs + immS;
UINT32 data;
CHECK_WRITEBREAK(adr);
data = read32(adr&~3);
switch(adr&3) {
case 3: data = (data & 0x00ffffff) | (rt<<24); break;
case 2: data = (data & 0x0000ffff) | (rt<<16); break;
case 1: data = (data & 0x000000ff) | (rt<< 8); break;
case 0: data = rt; break;
}
write32(adr&~3,data);
}
break;
case LB:
CHECK_READBREAK(rs+immS);
rt = (INT8)read8(rs+immS); break;
case LBU:
CHECK_READBREAK(rs+immS);
rt = read8(rs+immS); break;
case LH: {
UINT32 adr = rs + immS;
CHECK_READBREAK(rs+immS);
if (adr&1) { EXCEPTION(E_DBE); }
else { UINT32 tmp = (INT16)read16(adr); if (rtno) rt=tmp; }
}
break;
case LHU: {
UINT32 adr = rs + immS;
CHECK_READBREAK(adr);
if (adr&1) { EXCEPTION(E_DBE); }
else { UINT32 tmp = read16(adr); if (rtno) rt=tmp; }
}
break;
case LW: {
UINT32 adr = rs + immS;
CHECK_READBREAK(adr);
if (adr&3) { EXCEPTION(E_DBE); }
else { UINT32 tmp = read32(adr); if (rtno) rt=tmp; }
}
break;
case LWL: {
UINT32 adr = rs + immS;
UINT32 data;
CHECK_READBREAK(adr);
data = read32(adr&~3);
switch(adr&3) {
case 3: rt = data; break;
case 2: rt = (rt & 0x000000ff) | (data<< 8); break;
case 1: rt = (rt & 0x0000ffff) | (data<<16); break;
case 0: rt = (rt & 0x00ffffff) | (data<<24); break;
}
}
break;
case LWR: {
UINT32 adr = rs + immS;
UINT32 data;
CHECK_READBREAK(adr);
data = read32(adr&~3);
switch(adr&3) {
case 3: rt = (rt & 0xffffff00) | (data>>24); break;
case 2: rt = (rt & 0xffff0000) | (data>>16); break;
case 1: rt = (rt & 0xff000000) | (data>> 8); break;
case 0: rt = data; break;
}
}
break;
case SWC0: {
UINT32 adr = rs+immS;
CHECK_WRITEBREAK(adr);
if (adr&3) { EXCEPTION(E_DBE); }
else write32(adr,CPR0[rtno]);
}
break;
case LWC0: {
UINT32 adr = rs+immS;
CHECK_READBREAK(adr);
if (adr&3) { EXCEPTION(E_DBE); }
else CPR0[rtno] = read32(rs+immS);
}
break;
case SWC2: {
UINT32 adr = rs+immS;
CHECK_WRITEBREAK(adr);
if (adr&3) { EXCEPTION(E_DBE); }
else { cop2read(rtno,CPR2); write32(adr,CPR2[rtno]); }
}
break;
case LWC2: {
UINT32 adr = rs+immS;
CHECK_READBREAK(adr);
if (adr&3) { EXCEPTION(E_DBE); }
else { CPR2[rtno] = read32(adr); cop2write(rtno,CPR2); }
}
break;
default: NOT_IMPREMENT("??"); break;
}
reg.r[0] = 0;
}